/***************************************************************************
 *   Copyright (C) 2007 to 2009 by Andreas Theofilu                        *
 *   andreas@theosys.at                                                    *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation version 3 of the License.                *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/

/*
 * This code is heavily based on the work of <paul@ant.sbrk.co.uk>
 */
#include "gant.h"
#include <sys/select.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <termios.h>
#include <stdlib.h>
#include <assert.h>
#include <kmessagebox.h>
#include <klocale.h>
#include <qfileinfo.h>

static char  G50_KEY[] = "A8A423B9F55E63C1"; // garmin network key

static char sendack1[] = "4402320499990000";
//                        44                message from pc?
//                        ..02              message type
//                        ....32            don't know
//                        ......04          don't know
//                        ........9999      my id
//                        ............0000  maybe id is 4 bytes
static char sendack2[] = "4404010099990000";
//                        ..04              message type
//                        ....01            don't know
//                        ......00          don't know
static char sendack3[] = "4406010000000000";
//                        ..06              message type
//                        ....01            don't know
static char sendack4[] = "4403000000000000";
//                        ..03              message type, go to idle
//                        ....01            don't know

ant::ant ()
{
	qFile = false;
	commenabled = 1;
	rfn = cfn = 0;
}

ant::~ant ()
{
	if (qFile)
	   device.close ();

	qFile = false;
	rfn = cfn = 0;
}

/*
 * Set the device and store it inside the class
 */
bool ant::setDevice (const QFile &fl)
{
	if (qFile)
	{
	   device.close();
	   qFile = false;
	}

	device.setFileName (fl.fileName ());

	if (!device.exists ())
	{
	   KMessageBox::error (0, i18n("Device %1 does not exist!").arg(fl.fileName()));
	   return false;
	}

	if (!device.open (QIODevice::ReadWrite))
	{
	   KMessageBox::error (0, i18n("Error opening device %1.").arg(fl.fileName()),
	   	device.errorString());
	   return false;
	}

	qFile = true;
	return true;
}

bool ant::setDevice (const QString &fl)
{
QFile f;

	if (qFile)
	{
	   device.close ();
	   qFile = false;
	}

	f.setFileName (fl);
	return setDevice (f);
}

/*
 * Send a message to the opened device.
 */
bool ant::msg_send(uchar mesg, uchar *inbuf, uchar len)
{
uchar buf[MAXMSG];
ssize_t nw;
int i;
uchar chk = MESG_TX_SYNC;

	buf[0] = MESG_TX_SYNC;
	buf[1] = len;
	chk ^= len;
	buf[2] = mesg;
	chk ^= mesg;
	
	for (i = 0; i < len; i++)
	{
	   buf[3+i] = inbuf[i];
	   chk ^= inbuf[i];
	}
	
	buf[3+i] = chk;
	usleep (10 * 1000);

	if ((4 + i) != (nw = write(device.handle(), buf, 4 + i)))
	{
	   KMessageBox::error (0, i18n("Error writing to device %1").arg(device.fileName()));
	   return false;
	}

	return true;
}

// two argument send
bool ant::msg_send(uchar mesg, uchar data1, uchar data2)
{
uchar buf[2];

	buf[0] = data1;
	buf[1] = data2;
	return msg_send(mesg, buf, 2);
}

// three argument send
bool ant::msg_send(uchar mesg, uchar data1, uchar data2, uchar data3)
{
uchar buf[3];

	buf[0] = data1;
	buf[1] = data2;
	buf[2] = data3;
	return msg_send(mesg, buf, 3);
}

bool ant::commfn ()
{
fd_set readfds, writefds, exceptfds;
int ready, fd;
struct timeval to;

	fd = device.handle ();

	for(;;)
	{
	   FD_ZERO(&readfds);
	   FD_ZERO(&writefds);
	   FD_ZERO(&exceptfds);
	   FD_SET(fd, &readfds);
	   to.tv_sec = 1;
	   to.tv_usec = 0;
	   ready = select(fd+1, &readfds, &writefds, &exceptfds, &to);

	   if (ready)
	   {
	      if (!get_data(fd))
		 return false;
	   }
	}

	return true;
}

bool ant::get_data(int fd)
{
static uchar buf[500];
static int bufc = 0;
int nr;
int dlen;
int i;
int j;
unsigned char chk = 0;
uchar event;
int found;
int srch;
int next;

	nr = read(fd, buf+bufc, 20);
	
	if (nr > 0)
	   bufc += nr;
	else
	   return true;

	if (bufc > 300)
	{
	   KMessageBox::error (0, i18n(">>buf<< too long!"));
	   return false;
	}

	// some data in buf
	// search for possible valid messages
	srch = 0;
	
	while (srch < bufc)
	{
	   found = 0;

	   for (i = srch; i < bufc; i++)
	   {
	      if (buf[i] == MESG_TX_SYNC)
	      {
		 if (i+1 < bufc && buf[i+1] >= 1 && buf[i+1] <= 13)
		 {
		    dlen = buf[i+1];

		    if ((i + 3 + dlen) < bufc)
		    {
		       chk = 0;

		       for (j = i; j <= i+3+dlen; j++)
			  chk ^= buf[j];

		       if (0 == chk)
		       {
			  found = 1; // got a valid message
			  break;
		       }
		       else
			  fprintf (stderr, "bad chk %02x\n", chk);
		    }
		 }
	      }
	   }

	   if (found)
	   {
	      next = j;
	      // got a valid message, see if any data needs to be discarded
	      event = 0;

	      switch (buf[i+2])
	      {
		 case MESG_RESPONSE_EVENT_ID:
		    if (rfn)
		    {
		       memcpy(rbufp, buf+i+3, dlen);

		       if (!(this->*rfn)(buf[i+3], buf[i+5]))
			  return false;
		    }
		 break;

		 case MESG_BROADCAST_DATA_ID:
		    event = EVENT_RX_BROADCAST;
		 break;

		 case MESG_ACKNOWLEDGED_DATA_ID:
		    event = EVENT_RX_ACKNOWLEDGED;
		 break;

		 case MESG_BURST_DATA_ID:
		    event = EVENT_RX_BURST_PACKET;
		 break;

		 case MESG_EXT_BROADCAST_DATA_ID:
		    event = EVENT_RX_EXT_BROADCAST;
		 break;

		 case MESG_EXT_ACKNOWLEDGED_DATA_ID:
		    event = EVENT_RX_EXT_ACKNOWLEDGED;
		 break;

		 case MESG_EXT_BURST_DATA_ID:
		    event = EVENT_RX_EXT_BURST_PACKET;
		 break;

		 default:
		    if (rfn)
		    {
		       // should be this according to the docs, but doesn't fit
		       if (dlen > MESG_DATA_SIZE)
		       {
			  KMessageBox::error(0, i18n("rresponse buffer too small!"));
			  return false;
		       }

		       memcpy(rbufp, buf+i+3, dlen);

		       if (!(this->*rfn)(buf[i+3], buf[i+2]))
			  return false;
		    }
	      }

	      if (event)
	      {
		 if (cfn)
		 {
		    if (dlen > MESG_DATA_SIZE)
		    {
		       KMessageBox::error(0, i18n("cresponse buffer too small!"));
		       return false;
		    }

		    memcpy(cbufp, buf+i+4, dlen);

		    if (!(this->*cfn)(buf[i+3], event))
		       return false;
		 }
	      }

	      srch = next;
	   }
	   else
	      break;
	}

	if (next < bufc)
	{
	   memmove(buf, buf+next, bufc-next);
	   bufc -= next;
	}
	else
	   bufc = 0;

        return true;
}

bool ant::ANT_ResetSystem()
{
uchar filler = 0;

	return msg_send(MESG_SYSTEM_RESET_ID, &filler, 1);
}

bool ant::ANT_Cmd55(uchar chan)
{
	return msg_send(0x55, &chan, 1);
}

bool ant::ANT_OpenRxScanMode (uchar chan)
{
	return msg_send(MESG_OPEN_RX_SCAN_ID, &chan, 1);
}

bool ant::ANT_Init ()
{
//char dev[40];
struct termios tp;

	if (!qFile)
	   return false;

	if (tcgetattr(device.handle(), &tp) < 0)
	{
	   KMessageBox::error(0, i18n("Error getting terminal attributes!"));
	   return false;
	}

	tp.c_iflag &=
	~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON|IXOFF|IXANY|INPCK|IUCLC);
	tp.c_oflag &= ~OPOST;
	tp.c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN|ECHOE);
	tp.c_cflag &= ~(CSIZE|PARENB);
	tp.c_cflag |= CS8 | CLOCAL | CREAD | CRTSCTS;

	if (cfsetispeed(&tp, B115200) < 0)
	{
	   KMessageBox::error(0, i18n("Error setting input speed of line terminal!"));
	   return false;
	}

	if (cfsetospeed(&tp, B115200) < 0)
	{
	   KMessageBox::error(0, i18n("Error setting output speed of line terminal!"));
	   return false;
	}

	tp.c_cc[VMIN] = 1;
	tp.c_cc[VTIME] = 0;

	if (tcsetattr(device.handle (), TCSANOW, &tp) < 0)
	{
	   KMessageBox::error(0, i18n("Error setting terminal attributes!"));
	   return false;
	}

//	return commfn ();
	return true;
}

bool ant::ANT_RequestMessage (uchar chan, uchar mesg)
{
	return msg_send(MESG_REQUEST_ID, chan, mesg);
}

bool ant::ANT_SetNetworkKeya (uchar net, uchar *key)
{
uchar buf[9];
int i;

	if (strlen((char *)key) != 16)
	{
	  fprintf(stderr, "Bad key length %s\n", key);
	  return 0;
	}

	buf[0] = net;

	for (i = 0; i < 8; i++)
	   buf[1+i] = hexval(key[i*2])*16+hexval(key[i*2+1]);

	return msg_send(MESG_NETWORK_KEY_ID, buf, 9);
}

bool ant::ANT_SetNetworkKey (uchar net, uchar *key)
{
uchar buf[9];
//int i;

	buf[0] = net;
	memcpy(buf+1, key, 8);
	return msg_send(MESG_NETWORK_KEY_ID, buf, 9);
}

bool ant::ANT_AssignChannel (uchar chan, uchar chtype, uchar net)
{
	return msg_send(MESG_ASSIGN_CHANNEL_ID, chan, chtype, net);
}

bool ant::ANT_UnAssignChannel (uchar chan)
{
	return msg_send(MESG_UNASSIGN_CHANNEL_ID, &chan, 1);
}

bool ant::ANT_SetChannelId (uchar chan, ushort dev, uchar devtype, uchar manid)
{
uchar buf[5];

	buf[0] = chan;
	buf[1] = dev%256;
	buf[2] = dev/256;
	buf[3] = devtype;
	buf[4] = manid;
	return msg_send(MESG_CHANNEL_ID_ID, buf, 5);
}

bool ant::ANT_SetChannelRFFreq (uchar chan, uchar freq)
{
	return msg_send(MESG_CHANNEL_RADIO_FREQ_ID, chan, freq);
}

bool ant::ANT_SetChannelPeriod (uchar chan, ushort period)
{
uchar buf[3];

	buf[0] = chan;
	buf[1] = period%256;
	buf[2] = period/256;
	return msg_send(MESG_CHANNEL_MESG_PERIOD_ID, buf, 3);
}

bool ant::ANT_SetChannelSearchTimeout (uchar chan, uchar timeout)
{
	return msg_send(MESG_CHANNEL_SEARCH_TIMEOUT_ID, chan, timeout);
}

bool ant::ANT_SetSearchWaveform (uchar chan, ushort waveform)
{
uchar buf[3];

	buf[0] = chan;
	buf[1] = waveform % 256;
	buf[2] = waveform / 256;
	return msg_send(MESG_SEARCH_WAVEFORM_ID, buf, 3);
}

bool ant::ANT_SendAcknowledgedDataA (uchar chan, uchar *data) // ascii version
{
uchar buf[9];
int i;

	if (strlen((char *)data) != 16)
	{
	   fprintf(stderr, "Bad data length %s\n", data);
	   return false;
	}

	buf[0] = chan;

	for (i = 0; i < 8; i++)
	   buf[1+i] = hexval (data[i*2]) * 16 + hexval(data[i*2+1]);

	return msg_send(MESG_ACKNOWLEDGED_DATA_ID, buf, 9);
}

bool ant::ANT_SendAcknowledgedData (uchar chan, uchar *data)
{
uchar buf[9];
//int i;

	buf[0] = chan;
	memcpy(buf+1, data, 8);
	return msg_send(MESG_ACKNOWLEDGED_DATA_ID, buf, 9);
}

unsigned short ant::ANT_SendBurstTransferA(uchar chan, uchar *data, unsigned short numpkts)
{
uchar buf[9];
int i;
int j;
int seq = 0;

	fprintf(stderr, "numpkts %d data %s\n", numpkts, data);

	if (strlen((char *)data) != (16 * numpkts))
	{
	   fprintf(stderr, "Bad data length %s numpkts %d\n", data, numpkts);
	   return 0;
	}

	for (j = 0; j < numpkts; j++)
	{
	   buf[0] = chan | (seq << 5) | ((j == (numpkts - 1)) ? 0x80 : 0);

	   for (i = 0; i < 8; i++)
	      buf[1+i] = hexval (data[j*16+i*2]) * 16 + hexval (data[j*16+i*2+1]);
	
	   usleep(20 * 1000);
	   msg_send(MESG_BURST_DATA_ID, buf, 9);
	   seq++;

	   if (seq > 3)
	      seq = 1;
	}

	return numpkts;
}

unsigned short ant::ANT_SendBurstTransfer (uchar chan, uchar *data, unsigned short numpkts)
{
uchar buf[9];
//int i;
int j;
int seq = 0;

	for (j = 0; j < numpkts; j++)
	{
	   buf[0] = chan | (seq << 5) | ((j == (numpkts - 1)) ? 0x80 : 0);
	   memcpy (buf+1, data+j*8, 8);
	   usleep (20*1000);
	   msg_send (MESG_BURST_DATA_ID, buf, 9);
	   seq++;

	   if (seq > 3)
	      seq = 1;
	}

	return numpkts;
}

bool ant::ANT_OpenChannel (uchar chan)
{
	return msg_send(MESG_OPEN_CHANNEL_ID, &chan, 1);
}

bool ant::ANT_CloseChannel (uchar chan)
{
	return msg_send(MESG_CLOSE_CHANNEL_ID, &chan, 1);
}

void ant::ANT_AssignResponseFunction (RESPONSE_FUNC rf, uchar* rbuf)
{
	rfn = rf;
	rbufp = rbuf;
}

void ant::ANT_AssignChannelEventFunction (uchar, CHANNEL_EVENT_FUNC rf, uchar* rbuf)
{
	cfn = rf;
	cbufp = rbuf;
}

int ant::ANT_fd()
{
	return device.handle();
}

/*
 * Following functions control the device and uses the class "ant".
 * This is class "gant".
 */

gant::gant (const QString &af)
{
	mydev = 0;
	peerdev = 0;
	myid = 0;
	state = 0;
	authfd = false;

	faf.setFileName (af);

	if (!faf.open (QIODevice::ReadWrite))
	{
	   KMessageBox::error (0, i18n("Error opening device %1.").arg(af),
	   	faf.errorString());
	}

	authfile = af;
	authfd = true;
	tmpOut.setFileName(QString(tmpnam(NULL)));
}

gant::~gant ()
{
	if (authfd)
	   faf.close();

	// if the file is still open, this function closes it before
	// it is removed.
	tmpOut.remove();
}

uint gant::randno ()
{
	return (uint)random ();
}

bool gant::chevent (uchar chan, uchar event)
{
uchar seq;
uchar last;
uchar status = cbuf[1];
uchar phase = cbuf[2];
struct ack_msg ack;
struct auth_msg auth;
struct pair_msg pair;
uint id;
//int i;

	//fprintf(stderr, "state %d\n", state);
/*	if (dbg && event != EVENT_RX_BURST_PACKET) {
		fprintf(stderr, "chan %d event %02x channel open: ", chan, event);
		for (i = 0; i < 8; i++)
			fprintf(stderr, "%02x", cbuf[i]);
		fprintf(stderr, "\n");
	}
*/
	// transition between garmin phases handled via state machine
	switch (event)
	{
	   case EVENT_RX_BROADCAST:
	      memcpy((void *)&id, cbuf+4, 4);

	      if (state == 1 && (phase & 7) == 0)
	      {
		 // received broadcast from watch in phase 0
		 state++;

		 if ((status & 8) == 8)
		 {
		    // pairing
		    myid = randno();
		    fprintf(stderr, "pairing, generated id %08x\n", myid);
		 }
		 else
		 {
		    // garmin moved to phase 1 in response to sendack1
		    int nr;
//		    printf("reading auth data from %s\n", authfile);
		    authfd = open(authfile.toAscii(), O_RDONLY);

		    if (!authfd || faf.size () < 32)
		    {
		       KMessageBox::error(0, i18n("There is no authfile available or it has wrong size!"));
		       return false;
		    }

		    nr = read(faf.handle(), authdata, 32);

		    if (nr != 32)
		    {
		       KMessageBox::error(0, i18n ("Error reading auth file %1!").arg(authfile));
		       return false;
		    }

		    memcpy((void *)&myauth1, authdata+16, 4);
		    memcpy((void *)&myauth2, authdata+20, 4);
		    memcpy((void *)&mydev, authdata+12, 4);
		    memcpy((void *)&myid, authdata+4, 4);
		 }

		 if (status & 0x20)
		    fprintf(stderr, "watch contains NEW data\n");

		 ANT_RequestMessage(chan, MESG_CHANNEL_ID_ID); /* request sender id */
	      }
	      else if (state == 3 && phase == 1)
	      {
		 state++;
		 ack.code = 0x44;
		 ack.atype = 4;
		 ack.c1 = 0x01;
		 ack.c2 = 0x00;
		 ack.id = myid;
		 ANT_SendAcknowledgedData(chan, (uchar *)&ack); // tell garmin to send id data
	      }
	      else if (state == 5 && phase == 1)
	      {
		 if ((status & 0x0f) == 4)
		 {
		    // received id/version or whatever
		    state++;
		    assert(sizeof auth == AUTHSIZE);
		    auth.code = 0x44;
		    auth.atype = 4;
		    auth.phase = 3;
		    auth.u1 = 8;
		    auth.id = myid;
		    auth.auth1 = myauth1;
		    auth.auth2 = myauth2;
		    auth.fill1 = auth.fill2 = 0;
		    ANT_SendBurstTransfer(chan, (uchar *)&auth, (sizeof auth)/8); // send our auth data
		 }
		 else if ((status & 0x0f) == 0x0c)
		 {
		     // pairing
		     assert(sizeof pair == PAIRSIZE);
		     state = 10;
		     pair.code = 0x44;
		     pair.atype = 4;
		     pair.phase = 2;
		     pair.u1 = 7;
		     pair.id = myid;
		     bzero(pair.devname, sizeof pair.devname);

		    if (peerdev <= 99999999) // only allow 8 digits
		       sprintf(pair.devname, "%d", peerdev);
		    else
		       fprintf(stderr, "pair dev name too large %08x \"%d\"\n", peerdev, peerdev);

//		    printf("sending pair data for dev %s\n", pair.devname);
		    ANT_SendBurstTransfer(chan, (uchar *)&pair, (sizeof pair)/8) ; // send pair data
		 }
		 else
		 {
		    fprintf(stderr, "error in gant.cpp on line %d\n", __LINE__);
		    return false;
		 }
	      }
	      else if (state == 6 && (status & 0x0f) == 4 && phase == 2)
	      {
		 // if our auth is ok, garmin has gone to phase 2
		 state++;
		 ack.code = 0x44;
		 ack.atype = 6;
		 ack.c1 = 0x01;
		 ack.c2 = 0x00;
		 ack.id = 0;
		 ANT_SendAcknowledgedData(chan, (uchar *)&ack); // tell garmin to start upload
	      }
	      else if (state == 8 && phase == 2)
	      {
		 // upload finished. received broadcast that still in phase 2
		 state++;
		 ack.code = 0x44;
		 ack.atype = 3;
		 ack.c1 = 0x00;
		 ack.c2 = 0x00;
		 ack.id = 0;
		 ANT_SendAcknowledgedData(chan, (uchar *)&ack); // tell garmin we're finished
	      }
	      else if (state == 9 && phase == 0)
	      {
		 // garmin replies it's back in phase 0
		 fprintf(stderr, "finished\n");
		 return true;
	      }
	      else if (state == 1 && phase != 0)
	      {
		 // don't know what phase we're in. let's try and reset
		 fprintf(stderr, "resetting\n");
		 ack.code = 0x44;
		 ack.atype = 3;
		 ack.c1 = 0x00;
		 ack.c2 = 0x00;
		 ack.id = 0;
		 ANT_SendAcknowledgedData(chan, (uchar *)&ack); // tell garmin we're finished
		 sleep(1);
		 return false;
	      }
	      else if (state == 20 && phase == 2)
	      {
		 // upload finished. tell garmin to delete logs
		 state++;
		 ack.code = 0x44;
		 ack.atype = 0x0b;
		 ack.c1 = 0x01;
		 ack.c2 = 0x00;
		 ack.id = 0;
		 ANT_SendAcknowledgedData(chan, (uchar *)&ack); // delete logs
	      }
	      else if (state == 21 && phase == 2)
	      {
		 state = 8;
	      }
	   break;

	   case EVENT_RX_BURST_PACKET:
	      seq = (chan & 0x60) >> 5;
	      last = (chan & 0x80) >> 7;
	      chan &= 0x1f;

	      if (state == 4)
	      {
		 static int once = 0;
		 // garmin sending authentication/identification data

		 if (!once)
		    once = 1;

		 memcpy(clientid[seq], cbuf, 8);

		 if (last)
		 {
		    state++;

		    memcpy(&peerdev, clientid[1]+4, 4);

		    if (mydev != 0 && peerdev != mydev)
		    {
		       fprintf(stderr, "Don't know this device %08x != %08x\n", peerdev, mydev);
		       return false;
		    }
		 }
	      }
	      else if (state == 7)
	      {
		 static int once = 0;
		 int nw;

		 // garmin uploading in response to sendack3
		 // in this state we're receiving the workout data
		 if (!once)
		 {
		    fprintf(stderr, "receiving\n");
		    once = 1;
		    tmpOut.open (QIODevice::ReadWrite | QIODevice::Truncate);
		 }

		 // FIXME: Here we should fill our buffer, instead of writing
		 // everything into a file.
		 nw = write(tmpOut.handle(), cbuf, 8);

		 if (nw != 8)
		 {
		    KMessageBox::error(0, i18n ("Failed to write to a temporary file!"));
		    return false;
		 }

		 if (last)
		 {
		    state++;    // just to exit
				//state = 20; // to delete logs
		    tmpOut.close();
		 }
	      }
	      else if (state == 10)
	      {
		 // receiving auth data
		 static int once = 0;
		 int nw;

		 if (!once)
		 {
//		    printf("storing auth data in %s\n", authfile);
		    once = 1;
//		    authfd = open(authfile, O_WRONLY|O_CREAT, 0644);

/*		    if (authfd < 0)
		    {
		       perror(authfile);
		       exit(1);
		    } */
		 }

		 nw = write(faf.handle(), cbuf, 8);

		 if (nw != 8)
		 {
		    KMessageBox::error(0, i18n ("Write to auth file %1 failed!").arg(authfile));
		    return false;
		 }

		 if (last)
		 {
		    //state = 6; // to download during pairing
		    state = 8; // to finish at end of pairing
		 }
	      }
	      else if (state == 6)
	      {
		 // response to authentication
		 static int once = 0;
//		 int i;

		 if (!once)
		 {
		    once = 1;
		 }

		 if (last)
		 {
		    if (cbuf[2] == 2)
		    {
		       fprintf(stderr, "authentication failed\n");
		       return false;
		    }
		 }
	      }
	      else
	      {
		 int i;

		 fprintf(stderr, "data in state %d: ", state);

		 for (i = 0; i < 8; i++)
		    fprintf(stderr, "%02x", cbuf[i]);

		 fprintf(stderr, "\n");
	      }
	   break;
	}

	return 1;
}

bool gant::revent (uchar chan, uchar event)
{
unsigned short devid;
struct ack_msg ack;
int i;

	switch (event)
	{
	   case EVENT_TRANSFER_TX_COMPLETED:
	      // ignore
	      // printf("Transfer complete %02x\n", ebuf[1]);
	   break;

	   case INVALID_MESSAGE:
	      fprintf(stderr, "Invalid message %02x\n", ebuf[1]);
	   break;

	   case RESPONSE_NO_ERROR:
	      switch (ebuf[1])
	      {
		 case MESG_ASSIGN_CHANNEL_ID:
		    ANT_AssignChannelEventFunction((uchar)chan, (CHANNEL_EVENT_FUNC)&gant::chevent, (uchar *)&cbuf);
		 break;

		 case MESG_OPEN_CHANNEL_ID:
		    state++;
		    fprintf(stderr, "channel open (%d), waiting for broadcast\n", state);
		 break;

		 default:
		    // ignore
		    // printf("Message %02x NO_ERROR\n", ebuf[1]);
		 break;
	      }
	   break;

	   case MESG_CHANNEL_ID_ID:
	      devid = ebuf[1]+ebuf[2]*256;

	      if (mydev == 0 || devid == mydev%65536)
	      {
		 state++;
		 ack.code = 0x44; ack.atype = 2; ack.c1 = 0x32; ack.c2 = 0x04;
		 ack.id = myid;
		 ANT_SendAcknowledgedData(chan, (uchar *)&ack); // tell watch go to phase 1
	      }
	      else
	      {
		 fprintf(stderr, "Ignoring unknown device %08x, mydev %08x\n", devid, mydev);
	      }
	   break;

	   case MESG_NETWORK_KEY_ID:
	   case MESG_SEARCH_WAVEFORM_ID:
	   case MESG_OPEN_CHANNEL_ID:
	      fprintf(stderr, "response event %02x code %02x\n", event, ebuf[2]);

	      for (i = 0; i < 8; i++)
		 fprintf(stderr, "%02x", ebuf[i]);

	      fprintf(stderr, "\n");
	   break;

	   case MESG_CAPABILITIES_ID:
	   break;

	   case MESG_CHANNEL_STATUS_ID:
	   break;

	   default:
	      fprintf(stderr, "Unhandled response event %02x\n", event);
	   break;
	}

	return true;
}

bool gant::read_device ()
{
//int devnum = 0;
int chan = 0;
int net = 0;
int chtype = 0; // wildcard
int devno = 0; // wildcard
int devtype = 0; // wildcard
int manid = 0; // wildcard
int freq = 0x32; // garmin specific radio frequency
int period = 0x1000; // garmin specific broadcast period
int srchto = 255; // max timeout
int waveform = 0x0053; // aids search somehow

	// Check if we already have a device set.
//	if (!qFile)
//	   return false;

	// TODO: Do this properly...
/*	if (ac > 1) {
		authfile = av[1];
	}
	else {
		fprintf(stderr, "need auth file\n");
		exit(1);
	}
		
	if (ac > 2)
		fn = av[2]; // store the output filename for event function
	if (ac > 3)
		devnum = atoi(av[3]);
	if (ac > 4)
		myid = atoi(av[4]);
	if (ac > 5)
		mydev = atoi(av[5]);
*/
	if (!ANT_Init())
	   return false;

	if (!ANT_ResetSystem())
	   return false;

	ANT_AssignResponseFunction((RESPONSE_FUNC)&gant::revent, (uchar *)&ebuf);

	if (!ANT_RequestMessage(chan, MESG_CHANNEL_STATUS_ID))	//informative
	   return false;

	if (!ANT_SetNetworkKeya(net, (uchar *)G50_KEY))
	   return false;

	if (!ANT_AssignChannel(chan, chtype, net))
	   return false;

	if (!ANT_SetChannelId(chan, devno, devtype, manid))
	   return false;

	if (!ANT_RequestMessage(chan, MESG_CAPABILITIES_ID))	//informative
	   return false;

	if (!ANT_SetChannelRFFreq(chan, freq))
	   return false;

	if (!ANT_SetChannelPeriod(chan, period))
	   return false;

	if (!ANT_SetChannelSearchTimeout(chan, srchto))
	   return false;

	if (!ANT_SetSearchWaveform(chan, waveform))
	   return false;

	if (!ANT_OpenChannel(chan))	// success for this bumps us to state 1
	   return false;

	if (!ANT_RequestMessage(chan, MESG_CHANNEL_STATUS_ID))	//informative
	   return false;

	// everything handled in event functions
//	for(;;)
//		sleep(10);

	return commfn ();
}

uchar *gant::getBuffer (int *size)
{
QFileInfo fi;
uchar *buffer;
long sz;

	fi.setFile (tmpOut);
	
	if (!fi.exists() || fi.size() > 1000000)
	   return 0;

	sz = fi.size();
	*size = 0;

	if (!(buffer = new uchar[sz+1]))
	{
	   KMessageBox::error(0, i18n("Error allocating %1 bytes of memory!").arg(sz+1));
	   return 0;
	}

	if (tmpOut.handle() == -1)
	{
	   if (!tmpOut.open(QIODevice::ReadOnly))
	   {
	      KMessageBox::error(0, i18n("Error opening a temporary file for reading!"), tmpOut.errorString());
	      delete buffer;
	      return 0;
	   }
	}

	if (read (tmpOut.handle(), buffer, sz) < sz)
	{
	   KMessageBox::error(0, i18n("Error reading from a temporary file!"));
	   tmpOut.close();
	   delete buffer;
	   return 0;
	}

	*size = (int)sz;
	return buffer;
}
